using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;
using AntEater.ComponentModel.BuildElements;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Represents a single build file.
    /// </summary>
    [Serializable]
    public class BuildFile : INotifyPropertyChanged
    {
        /// <summary>
        /// Occurs when the instance or some of his child objects has changed.
        /// </summary>
        public event EventHandler<EventArgs> Changed;

        /// <summary>
        /// Occurs when a property of the instance has changed
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="BuildFile"/> class.
        /// </summary>
        public BuildFile()
            : this(string.Empty) {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BuildFile"/> class.
        /// </summary>
        /// <param name="buildFilePath">The build file path.</param>
        public BuildFile(string buildFilePath)
            : base() {
            if (buildFilePath == null) { throw new ArgumentNullException("filename"); }

            // Parse name of build file
            int index = buildFilePath.LastIndexOf(Path.DirectorySeparatorChar);
            if (index < 0) {
                index = 0;
            }

            this._name = buildFilePath.Substring(index + 1);
            this._buildFilePath = buildFilePath;
            this._externalBuildProperties = new ExternalBuildPropertyCollection();
            this._externalBuildProperties.Changed += new EventHandler<EventArgs>(ExternalBuildPropertiesChanged);

            this._messages = new MessageCollection();
            this._messages.Changed += new EventHandler<EventArgs>(MessagesChanged);
        }

        private string _buildFilePath;

        /// <summary>
        /// Gets the build file path.
        /// </summary>
        /// <value>The build file path.</value>
        public string BuildFilePath {
            get { return _buildFilePath; }
        }

        private string _name;

        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name {
            get { return _name; }
        }

        [NonSerialized()]
        private BuildFileDefinition _definition;

        /// <summary>
        /// Gets the definition.
        /// </summary>
        /// <value>The definition.</value>
        [XmlIgnore()]
        public BuildFileDefinition Definition {
            get { return _definition; }
            set {
                if (_definition != value) {
                    if (_definition != null) {
                        _definition.Changed -= new EventHandler<EventArgs>(this.DefinitionChanged);
                    }

                    _definition = value;
                    _definition.Changed += new EventHandler<EventArgs>(this.DefinitionChanged);
                    this.OnPropertyChanged("Definition");
                }
            }
        }

        [NonSerialized()]
        private MessageCollection _messages;

        /// <summary>
        /// Gets the messages.
        /// </summary>
        /// <value>The messages.</value>
        [XmlIgnore()]
        public MessageCollection Messages {
            get { return _messages; }
        }

        private ExternalBuildPropertyCollection _externalBuildProperties;

        /// <summary>
        /// Gets the external build properties.
        /// </summary>
        /// <value>The external build properties.</value>
        public ExternalBuildPropertyCollection ExternalBuildProperties {
            get { return _externalBuildProperties; }
        }

        /// <summary>
        /// Definitions the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void DefinitionChanged(object sender, EventArgs e) {
            this.OnChanged();
        }

        /// <summary>
        /// Externals the build properties changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ExternalBuildPropertiesChanged(object sender, EventArgs e) {
            this.OnChanged();
        }

        /// <summary>
        /// Messageses the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void MessagesChanged(object sender, EventArgs e) {
            this.OnChanged();
        }

        /// <summary>
        /// Called when [changed].
        /// </summary>
        protected void OnChanged() {
            if (this.Changed != null) {
                this.Changed(this, new EventArgs());
            }
        }

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected void OnPropertyChanged(string propertyName) {
            if (this.PropertyChanged != null) {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }

            this.OnChanged();
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString() {
            string result = string.Empty;

            if (!string.IsNullOrEmpty(_name)) {
                result += _name;
            }

            if (string.IsNullOrEmpty(result)) {
                result = base.ToString();
            }

            return result;
        }
    }
}
